/**
 * 一个累加器的例子
 * Oct 24, 2010, coanor
 */
template <typename T>
inline T accum(T const* beg, T const* end)
{
	T total =  T();	/* assume T() generatea value equals to 0 */
	while (beg !=  end) {
		total += *beg;
		++beg;
	}
	return total;
}

/*
 * 在上面的代码中，对于诸如int和float类型的内建值类型而言，T()通常都
 * 产生一个等于0的值。
 *
 * 但当上面的模板函数计算字符串的平均值时，会有问题。
 *
 * 对于ansi字符而言，下面的代码期望输出97~122(只考虑小写字母)之间的值，
 * 但实际上其输出为-5.
 *
 * 这里的问题是，上面的模板是基于char类型进行实例化的，而char的范围太小，
 * 即使针对较小的数值进行计算也会导致越界的行为。
 */
void accum_string(void)
{
	char name[] = "templates";
	int len = sizeof(name);

	std::cout << "the average value of the string in\" "
	<< name << "\"is "
	/* accum调用导致值越界 */
	<< accum(&name[0], &name[len]) / len
	<< '\n';
}

/*
 * 为解决上面不同类型之间的差异，可以对accum所调用的每个T类型都创建一个
 * 关联，也即用来存储累加和的类型，这种关联类型可认为是T类型的一个特征(trait)，
 * 因而我们可以使用模板特例化来写出下面这坨代码：
 */
template<typename T>
class accum_traits:

template<>
class accum_traits<char>{
public:
	typedef int acct;
}

template<>
class accum_traits<short>{
public:
	typedef int acct;
}

template<>
class accum_traits<int>{
public:
	typedef long acct;
}

template<>
class accum_traits<unsigned int>{
public:
	typedef unsigned long acct;
}

template<>
class accum_traits<float>{
public:
	typedef double acct;
}

/*
 * 上面的代码中，模板accum_traits称作一个trait模板，因为它含有它的参数
 * 类型的一个trait(通常而言，可以存在多个trait和多个参数)。对该模板，并
 * 没有提供一个泛型的定义，因为在不知道参数类型的情况下，并不能选择一种
 * 类型来作为和的类型，然而可以利用某个实参类型，例如T：
 */
/* new accum template */
template<typename T>
inline typename accum_traits<T>::acct accume(T const* beg, T const* end)
{
	/* return type is a element's trait */
	typedef typename accum_traits<T>::acct acct;

	/* assume that acct() generate a value equals to 0 */
	acct total = acct();
	while (beg != end) {
		total += *beg;
		++beg;
	}

	return total;
}

/*
 * 在上面的代码中，我们假定了accum()模板使用缺省的构造函数的返回值来初始化
 * 结果变量(即将total初始化为0)，但并不能保证这个构造函数会返回一个符合条件
 * 的值，而且也不能保证有一个这样的构造函数。
 *
 * 我们为accum_traits新增一个trait,新的trait是一个常量，而常量是在编译时
 * 求值的，因此可以保证其初始值为0.
 */

template<typename T>
class accum_traits:

template<>
class accum_traits<char>{
public:
	typedef int acct;
	static acct const zero = 0;
}

template<>
class accum_traits<short>{
public:
	typedef int acct;
	static acct const zero = 0;
}

template<>
class accum_traits<int>{
public:
	typedef long acct;
	static acct const zero = 0;
}

template<>
class accum_traits<unsigned int>{
public:
	typedef unsigned long acct;
	static acct const zero = 0;
}

/*
 * 这样，新的accum模板如下:
 */
template<typename T>
inline typename accum_traits<T>::acct accume(T const* beg, T const* end)
{
	/* return type is a element's trait */
	typedef typename accum_traits<T>::acct acct;

	/* assume that acct() generate a value equals to 0 */
	acct total = accum_traits<T>::zero;
	while (beg != end) {
		total += *beg;
		++beg;
	}

	return total;
}

/*
 * 下面的做法是错误的，这也是本解决方案的一个缺点。C++只允许对整型和枚举
 * 类型初始化成静态成员变量，显然对于浮点类型的其它类型(也包括自定义类型)，
 * 就不能使用本解决方案.
 */
template<>
class accum_traits<float>{
public:
	typedef double acct;
	/* XXX: error */
	static acct const zero = 0;
}

/*
 * 对于浮点以及其它类型，一个直接的解决方案就是在类的内部定义这个value trait,
 * 然后在源文件中进行初始化：
 */
template<>
class accum_traits<float>{
public:
	typedef double acct;
	static double const zero;
}
/* src file */
double const accum_traits<float>::zero = 0.0;

/*
 * 但是这种方法也有一个显著的缺点，即对于编译器而言，它是不知道这种解决
 * 方案的，也即编译器通常都不会知道位于其它文件的定义，也即编译器根本不
 * 知道zero为0这个事实.
 * 
 * 于是我们使用函数调用的方式来实现上述效果,新的accum_traits出来了：
 */

template<typename T>
class accum_traits:

template<>
class accum_traits<char>{
public:
	typedef int acct;
	static acct zero() {
		return 0;
	}
}

template<>
class accum_traits<short>{
public:
	typedef int acct;
	static acct zero() {
		return 0;
	}
}

template<>
class accum_traits<int>{
public:
	typedef long acct;
	static acct zero() {
		return 0;
	}
}

template<>
class accum_traits<unsigned int>{
public:
	typedef unsigned long acct;
	static acct zero() {
		return 0;
	}
}

template<>
class accum_traits<float>{
public:
	typedef double acct;
	static acct zero() {
		return 0;
	}
}

/*
 * 对应用程序而言，这里的唯一区别就是使用函数调用的方式(而不是访问
 * 一个静态数据成员)
 */
template<typename T>
inline typename accum_traits<T>::acct accume(T const* beg, T const* end)
{
	/* return type is a element's trait */
	typedef typename accum_traits<T>::acct acct;

	/* a function call to get a zero value */
	acct total = accum_traits<T>::zero();
	while (beg != end) {
		total += *beg;
		++beg;
	}

	return total;
}
